package com.xiashitech.agent.instrumentation.base.context;

import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.context.ContextKey;

import java.util.function.BiConsumer;

/**
 * trace过程中需要传递的变量，对baggage进行补充
 * @author zhaoyk
 */
public interface TraceContextVars {

    ContextKey<TraceContextVars> CONTEXT_KEY = ContextKey.named("trace-context-vars");

    /**
     * 传递模式：贯穿
     */
    int PASS_MODE_THROUGH = 1;

    /**
     * 传递模式：重返
     */
    int PASS_MODE_REENTRY = 2;


    String get(String name);

    ContextVarEntry getEntry(String name);

    TraceContextVars set(String name, String value);

    TraceContextVars set(String name, String value, String metadata);

    TraceContextVars set(ContextVarName varName, String value);

    TraceContextVars set(ContextVarName varName, String value, String metadata);

    ContextVarName getVarName(String name);

    boolean remove(String name);

    int getVersion();

    static TraceContextVars get() {
        return fromContext(XSContext.current(), true);
    }

    static TraceContextVars fromContext(XSContext context, boolean autoBind) {
        TraceContextVars vars = context.get(CONTEXT_KEY);
        if(vars == null) {
            int initVersion = 0;

            String vStr = Baggage.current().getEntryValue(TraceConst.XS_CONTEXT_VARS_VERSION);
            if (vStr != null && !vStr.isEmpty())
                initVersion = Integer.parseInt(vStr);

            vars = empty(initVersion);

            if(autoBind)
                vars.storeInContext(context).makeCurrent();
        }
        return vars;
    }

    static TraceContextVars fromContext(XSContext context) {
        return fromContext(context, false);
    }

    static TraceContextVars empty(int initVersion) {
        return new TraceContextVarsImpl(initVersion);
    }

    default XSContext storeInContext(XSContext context) {
        return context.with(CONTEXT_KEY, this);
    }

    int size();

    default boolean isEmpty() {
        return this.size() == 0;
    }

    void forEach(BiConsumer<ContextVarName, ContextVarEntry> consumer);

}
